开发环境:
MDK:Keil 5.30
STM32CubeMX:V6.4.0
MCU:STM32F103ZET6
19.1程序加密工作原理
STM32通过读取芯片唯一ID号来实现程序的保护,防止被抄袭。96位的产品唯一身份标识所提供的参考号码对任意一个STM32微控制器,在任何情况下都是唯一的。用户在何种情况下,都不能修改这个身份标识。按照用户不同的用法,可以以字节(8位)为单位读取,也可以以半字(16位)或者全字(32位)读取。在这里要提醒读者,要注意大端小端模式。
19.2程序加密具体代码实现-标准库
其实读取ID很简单,如果存储ID的变量为8位。则需要读取12次,如下所示。
u8 Sys_ID[12],i;
for(i=0;i<12;i++)
{
Sys_ID[i]=*( uint8_t*)(0x1FFFF7E8+i);
printf(" %0.2X",Sys_ID[i]);
}
主函数代码如下:
/**
* @brief main
* @param None
* @retval None
*/
int main(void)
{
uint8_t Sys_ID[12],i;
/*系统时钟初始化*/
SysTick_Init();
/* USART1 config 115200 8-N-1 */
USART_Config();
for(i=0;i<12;i++)
{
Sys_ID[i]=*(uint8_t*)(0x1FFFF7E8+i);
printf(" %0.2X",Sys_ID[i]);
}
//ID 39 FF DF 05 4E 42 32 32 10 61 14 51
if(Sys_ID[0]==0x39 && Sys_ID[1]==0xFF && Sys_ID[2]==0xDF &&
Sys_ID[3]==0x05 && Sys_ID[4]==0x4E && Sys_ID[5]==0x42 &&
Sys_ID[6]==0x32 && Sys_ID[7]==0x32 && Sys_ID[8]==0x10 &&
Sys_ID[9]==0x61 && Sys_ID[10]==0x14 && Sys_ID[11]==0x51)
{
printf("\r\n通过\r\n");
}
else
{
printf("\r\n失败\r\n");
//while(1);
}
while(1);
}
如果存储ID的变量为32位。则需要读取3次。
u32 Sys_ID[3];
Sys_ID[2] = *(__IO u32*)(0X1FFFF7E8); // 低字节
Sys_ID[1] = *(__IO u32 *)(0X1FFFF7EC); //
Sys_ID[0] = *(__IO u32 *)(0X1FFFF7F0); // 高字节
STM32单片机的存储方式为小端模式。
【注】大小端
地址从小到大,先放低字节,再放高字节:小端模式
地址从小到大,先放高字节,再放低字节:大端模式
19.3程序加密具体代码实现-HAL库
其实读取ID很简单,如果存储ID的变量为8位。则需要读取12次,如下所示。
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t Sys_ID[12],i;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
for(i=0;i<12;i++)
{
Sys_ID[i]=*(uint8_t*)(0x1FFFF7E8+i);
printf(" %0.2X",Sys_ID[i]);
}
//ID 39 FF DF 05 4E 42 32 32 10 61 14 51
if(Sys_ID[0]==0x39 && Sys_ID[1]==0xFF && Sys_ID[2]==0xDF &&
Sys_ID[3]==0x05 && Sys_ID[4]==0x4E && Sys_ID[5]==0x42 &&
Sys_ID[6]==0x32 && Sys_ID[7]==0x32 && Sys_ID[8]==0x10 &&
Sys_ID[9]==0x61 && Sys_ID[10]==0x14 && Sys_ID[11]==0x51)
{
printf("\r\n通过\r\n");
}
else
{
printf("\r\n失败\r\n");
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
如果存储ID的变量为32位。则需要读取3次。
uint32_t Sys_ID[3];
Sys_ID[2] = *(__IO uint32_t *)(0X1FFFF7E8); // 低字节
Sys_ID[1] = *(__IO uint32_t *)(0X1FFFF7EC); //
Sys_ID[0] = *(__IO uint32_t *)(0X1FFFF7F0); // 高字节
19.4实验现象
将程序编译完成后下载到板子中,可以看到打印出来的唯一ID,该程序是通过现读取ID在通过ID判断,才会打印出ID后面的“通过”字样。
当然啦,每个芯片的ID是不一样。
欢迎访问我的网站
BruceOu的哔哩哔哩
BruceOu的主页
BruceOu的博客
BruceOu的CSDN博客
BruceOu的简书
BruceOu的知乎
资源获取方式
1.关注公众号[嵌入式实验楼]
2.在公众号回复关键词[Cortex-M]获取资料提取码